package com.dp1.deliversoft.algorithm;

import java.util.ArrayList;
import java.util.Iterator;

import com.dp1.deliversoft.entidad.Constantes;
import com.dp1.deliversoft.entidad.Mapa;
import com.dp1.deliversoft.entidad.Pedido;
import com.dp1.deliversoft.entidad.Ruta;
import com.dp1.deliversoft.entidad.Vehiculo;
import com.dp1.deliversoft.entidad.resultados.PaquetesdepedidoPorVehiculo;

public class AlgoritmoParticionZonas {
	Mapa mapita;
	AdministracionVehiculos av;
	ArrayList<Ruta> zonas;
	

	public AlgoritmoParticionZonas(Mapa mapita) {
		super();
		this.mapita = mapita;
	}
	
	public void partirZonasCentroGravedad(Ruta S)
	{
		ArrayList<Ruta> zonasListas = new ArrayList<Ruta>();
		ArrayList<Ruta> zonasPendientes = new ArrayList<Ruta>();
		ArrayList<Ruta> zonasInicial = new ArrayList<Ruta>();
		ArrayList<Ruta> l = new ArrayList<Ruta>();
		ArrayList<Ruta> lRHorizontal = new ArrayList<Ruta>();
		ArrayList<Ruta> lRVertical = new ArrayList<Ruta>();
		
		boolean estanZonasCompletas = true;
		zonasInicial.add(S);
		
		if (S.cantPaquetes()>25){
			estanZonasCompletas = zonasCompletas(zonasInicial, zonasListas, zonasPendientes);
		}
		else 
		{
			zonasListas.add(S);
		}
		
		ArrayList<Ruta> zonas1, zonas2;
		ArrayList<Integer> centro;
		Vehiculo vehiculo;

		int cx, cy;
		int costoHorizontal, costoVertical;
		Ruta S1, S2;
		
		Iterator<Ruta> it;
		Ruta r;
		
		while (zonasPendientes.size()>0)
		{
			it=zonasPendientes.iterator();
			r = it.next();
			while (!estanZonasCompletas){
				l.clear();
				lRHorizontal.clear();
				lRVertical.clear();
				centro = r.calcularCentroX(mapita);
				cx = centro.get(0);
				cy = centro.get(1);
				
				
				lRHorizontal = partirRutaEn2SegunCriterio(S, cx, cy, "H");
				costoHorizontal = (int) (lRHorizontal.get(0).getCostoRuta() + lRHorizontal
						.get(1).getCostoRuta()); // Falta calcular El costo de
													// las
				// Rutas en Horizontal

				
				lRVertical = partirRutaEn2SegunCriterio(S, cx, cy, "V");
				costoVertical = (int) (lRVertical.get(0).getCostoRuta() + lRVertical
						.get(1).getCostoRuta());

				if (costoHorizontal >= costoVertical) {
					S1 = lRHorizontal.get(0);
					S2 = lRHorizontal.get(1);
				} else {
					S1 = lRVertical.get(0);
					S2 = lRVertical.get(1);
				}
				l.add(S1);
				l.add(S2);
				zonasPendientes.remove(r);
				estanZonasCompletas = zonasCompletas(l, zonasListas, zonasPendientes);
			
			}
		}
		
		for (Ruta ruta : zonasListas)
		{
			for (int i = 0; i < ruta.getPedidos().size(); i++) {
				try
				{
					//System.out.println("bien"+i+"x: "+S.getPedidos().get(i).getPosX()+"y: "+S.getPedidos().get(i).getPosY());
					mapita.colocarCasa(ruta.getPedidos().get(i).getPosX()+1, ruta
							.getPedidos().get(i).getPosY()+1, "" + i);
				}
				catch (Exception e)
				{
					System.out.println("error"+i+"x: "+ruta.getPedidos().get(i).getPosX()+"y: "+ruta.getPedidos().get(i).getPosY());
				}
				
				// System.out.println("pedidos.add(new Pedido("+(S.getPedidos().get(i-1).getPosX()+1)+","+(S.getPedidos().get(i-1).getPosY()+1)+", 1, 1, 1));");
			}
		}
		
	}
	
	public ArrayList<Ruta> partirRutaEn2SegunCriterio(Ruta r, int cX, int cY, String criterio) {
	// Saco los pedidos de la ruta 'R' que viene de Parametro
		ArrayList<Pedido> pedidosApartir;
		pedidosApartir = r.getPedidos();

		// Creo los un ArrayLista de Pedidos que vamos a agregar a cada Ruta
		ArrayList<Pedido> pedido0 = new ArrayList<Pedido>();
		ArrayList<Pedido> pedido1 = new ArrayList<Pedido>();

		/*
		 * Para la particion Horizontal el pedido 0 es el Superior y el pedido 1
		 * es el Inferior
		 * 
		 * Para la particion Vertical el pedido 0 es la Izquierda y el pedido 1
		 * es la Derecha
		 */

		// Agrego los pedidos a los pedidos H Superior e Inferior
		for (int i = 0; i < pedidosApartir.size(); i++)
			if (criterio.equals("H")) {// Si es Horizontal
				if (pedidosApartir.get(i).getPosY() <= cY)
					pedido0.add(pedidosApartir.get(i));
				else
					pedido1.add(pedidosApartir.get(i));
			}// Si es Vertical
			else {
				if (pedidosApartir.get(i).getPosX() <= cX)
					pedido0.add(pedidosApartir.get(i));
				else
					pedido1.add(pedidosApartir.get(i));
			}

		/*
		 * Para la ruta Horizontal el pedido 0 es el Superior y el pedido 1 es
		 * el Inferior
		 * 
		 * Para la ruta Vertical el pedido 0 es la Izquierda y el pedido 1 es la
		 * Derecha
		 */

		Ruta ruta0 = new Ruta();
		Ruta ruta1 = new Ruta();

		ruta0.setPedidos(pedido0);
		ruta0.setCostoRuta(Calculos.calcularCostoRuta(pedido0));

		ruta1.setPedidos(pedido1);
		ruta1.setCostoRuta(Calculos.calcularCostoRuta(pedido1));

		/*
		 * ruta0 = Grasp.GraspPrincipal(pedido0, this.mapa); ruta1 =
		 * Grasp.GraspPrincipal(pedido1, this.mapa);
		 */

		// Defino un ArrayList donde van a estar las dos rutas
		ArrayList<Ruta> rutas = new ArrayList<Ruta>();

		// Agrego las Rutas divididas al ArrayList definido al inicio
		rutas.add(ruta0);
		rutas.add(ruta1);

		return rutas;
	}
	
	public static boolean zonasCompletas(ArrayList<Ruta> zonas, ArrayList<Ruta> zonasListas, ArrayList<Ruta> zonasTodavia )
	{
		boolean res = true;
		Iterator<Ruta> it;
		Ruta ruta;
		int tamanio = zonas.size(); 
		
		while (tamanio>0)
		{
			it=zonas.iterator();
			ruta = it.next();
			if (ruta.getPedidos().size()<=25) //entra en un vehiculo
			{
				zonas.remove(ruta);
				zonasListas.add(ruta); //y ademas asignarle un vehiculo
			}
			else
			{
				zonas.remove(ruta);
				zonasTodavia.add(ruta);
				res = false;
			}
			tamanio = zonas.size(); 
		}
		
		return res;
		
	}
	
	public ArrayList<Ruta> particionarRutaSimp(Ruta S) {
		Ruta r = new Ruta();
		ArrayList<Ruta> zonas = new ArrayList<Ruta>();
		Vehiculo v;
		int cantPaqIntroducir;
		ArrayList<Pedido> noSatisfechos = new ArrayList<Pedido>();
		ArrayList<Pedido> satisfechos = new ArrayList<Pedido>();
		
		for (Pedido pedido : S.getPedidos()) {
			noSatisfechos.add(pedido);
		}
		
		
		while (av.hayVehiculoDisponible_v2() && noSatisfechos.size()>0){
			r = new Ruta();
			boolean esAuto;
			if(contarPaquetesRestantes(noSatisfechos)>Constantes.cantPaquetesMoto)
			{
				v = av.getAutoDisponible_v2();
				esAuto = true;
			}
			else
			{
				v = av.getMotoDisponible_v2();
				esAuto = false; 
			}
			
			for (Pedido pedido : noSatisfechos) {
				if (pedido.getPaqRestantes()<=v.getCapDisponible()){
					//puedo meter todos los paquetes (o los restantes) en el vehiculo
					if (pedido.getPaqRestantes()>0){
						cantPaqIntroducir = pedido.getPaqRestantes();
						meterPaquetes(v, pedido, cantPaqIntroducir, satisfechos);
						r.getPedidos().add(pedido);
					}
				} else if (pedido.getPaqRestantes()>v.getCapDisponible()){
					if(pedido.getPaqRestantes()>0){
						cantPaqIntroducir = v.getCapDisponible();
						meterPaquetes(v, pedido, cantPaqIntroducir, satisfechos);
						r.getPedidos().add(pedido);
					}
				}
			}
			
			for (Pedido pedido : satisfechos) {
				noSatisfechos.remove(pedido);
			}
			
			v.setEstadoVehiculo(Vehiculo.EstRutaAsignada); //se cambia el estado del vehiculo
			r.setVehiculo(v); //a esta ruta se le asigna dicho vehiculo
			if (esAuto) //se actualiza la lista de vehiculos disponibles
			{
				av.getListaAutosDisponibles().remove(v);
			}
			else
			{
				av.getListaMotosDisponibles().remove(v);
			}
			zonas.add(r);
		}
		return zonas;
	}
	
	public void meterPaquetes(Vehiculo vehiculo, Pedido pedido, int cantPaqIntroducir, ArrayList<Pedido> entregados)
	{
		vehiculo.setCarga(vehiculo.getCarga()+cantPaqIntroducir);
		pedido.setPaqRestantes(pedido.getPaqRestantes()-cantPaqIntroducir);
		if (pedido.getPaqRestantes()==0){
			pedido.setEstadoAsignadoAruta(1);
			entregados.add(pedido);
			pedido.setEstado("ASIGNADO");
		}
		pedido.getPaquetesPorVehiculo().add(new PaquetesdepedidoPorVehiculo(pedido, vehiculo, cantPaqIntroducir));
	}
	
	public int contarPaquetesRestantes(ArrayList<Pedido> pedidos)
	{
		int cuentaPaquetes = 0;
			
		for (Pedido pedido: pedidos){
			cuentaPaquetes += pedido.getPaqRestantes();
		}
		return cuentaPaquetes;
	}
	
}
